P10-1. Grafana Tempo와 메시 분산 추적 - 이론 개념
Part 10 (이론): LGTM 트레이스 파이프라인 — Grafana Tempo와 메시 분산 추적 (OTLP · W3C Trace Context · TraceQL)
- 메트릭(Part 08)과 로그(Part 09)만으로는 여러 마이크로서비스를 거치는 요청의 병목 구간을 찾기 어려운 이유와, 분산 추적(Distributed Tracing) 이 이를 어떻게 해결하는지 설명할 수 있다.
- 분산 추적의 핵심 단위인
Trace,Span,Trace ID,Span ID,Parent Span ID의 관계(부모-자식 폭포수 구조)를 택배 운송장 비유로 완벽히 이해한다. - 서비스 메시(
Waypoint/ Envoy)가 코드 수정 없이 자동으로 해주는 일(Span 생성 · OTLP 전송 · 헤더 주입)과, 여러 홉을 이어 붙이는 표준 규약인W3C Trace Context(traceparent) 및B3헤더의 역할을 구분한다. - 차세대 트레이스 저장소인
Grafana Tempo의 특징과TraceQL쿼리 문법을 익힌다.
1. 왜 메트릭과 로그만으로는 부족할까? (분산 추적의 탄생)
고객이 쇼핑몰 앱에서 [결제하기] 버튼을 눌렀는데 화면이 5초 동안 멈췄다가 겨우 완료되었다고 해봅시다.
이 요청 1건이 처리되는 동안 내부에서는 프론트엔드 → 주문 API(order-api) → 재고 확인 API → 결제 API → 외부 PostgreSQL DB 까지 총 5개의 서버를 차례대로 거쳤습니다.
이때 우리가 메트릭만 보면 "아, 전체 응답 시간이 5초 걸렸구나" 는 알 수 있지만, 5개의 서버 중 누가 4.9초를 잡아먹은 범인인지 단번에 알기 어렵습니다. 그렇다고 5개 서버의 수만 줄짜리 로그를 다 열어서 "방금 그 철수 고객의 요청 로그가 어디 있지?" 하고 눈으로 대조하는 것은 사막에서 바늘 찾기입니다.
이 문제를 해결하기 위해 등장한 것이 바로 고객의 요청이 정문에 들어오는 순간 가슴에 고유한 바코드 스티커(Trace ID)를 딱 붙여서, 그 요청이 거쳐 가는 모든 프록시와 서버마다 출입 시각과 퇴장 시각을 도장으로 찍어 한 장의 엑스레이 사진(Waterfall 차트)으로 조립해 주는 기술, 즉 분산 추적(Distributed Tracing) 입니다!
2. 국제 택배 운송장으로 이해하는 Trace 와 Span 의 구조
분산 추적을 처음 배울 때 나오는 5가지 핵심 용어는 국제 택배 배송 조회 화면을 떠올리면 100% 이해됩니다.
flowchart TB
subgraph TRACE["하나의 전체 Trace (Trace ID: 4bf92f3577b34da6a3ce929d0e0e4736 · 총 소요시간: 3,015ms)"]
S1["[Root Span #1] study-client -> Waypoint
Span ID: aaa111 | Parent: 없음 (최초 출발!)
소요시간: 0ms ~ 3,015ms (전체 구간)"]
S2["[Child Span #2] Waypoint -> order-api-v1
Span ID: bbb222 | Parent: aaa111
소요시간: 2ms ~ 3,012ms (내부 호출)"]
S3["[Child Span #3] order-api-v1 -> pg-vm.mesh.internal:5432
Span ID: ccc333 | Parent: bbb222
소요시간: 5ms ~ 3,008ms (범인 검거: DB 쿼리가 3초 걸림!)"]
S1 --> S2 --> S3
endTrace, Span, Trace ID, Span ID, Parent Span ID)
Trace(트레이스 = 택배 1건의 전체 배송 여정):- 사용자의 요청 1건이 시스템에 들어와서 최종 응답이 나갈 때까지 거쳐 간 모든 구간의 기록을 하나로 묶은 전체 나무(Tree)입니다.
Trace ID(트레이스 ID = 32자리 글로벌 운송장 번호):- 요청이 처음 시작될 때 발급되는 전 세계 유일무이한 16바이트(32글자 16진수, 예:
4bf92f3577b34da6a3ce929d0e0e4736) 번호입니다. 이 요청이 10개의 서버를 거치더라도Trace ID는 끝까지 똑같은 번호를 유지합니다!
- 요청이 처음 시작될 때 발급되는 전 세계 유일무이한 16바이트(32글자 16진수, 예:
Span(스팬 = 각 물류센터 구간별 처리 기록):- 전체 여정(
Trace)을 이루는 각각의 단일 작업 조각입니다(예: "Waypoint가 요청을 받아 order-api로 전달한 구간"). - 각
Span안에는 구간 이름, 시작 시각, 걸린 시간(Duration), HTTP 상태 코드(http.status_code=200), 파드 이름 같은 상세 꼬리표(Attributes/Tags)가 들어 있습니다.
- 전체 여정(
Span ID와Parent Span ID(부모-자식 족보 번호):- 택배가 인천 물류센터(
Span ID: aaa111)를 거쳐 대전 허브(Span ID: bbb222)로 갔다면, 대전 허브의 기록지에는 "내 직전 출발지(부모,Parent Span ID)는aaa111번이다!" 라고 적혀 있습니다. - 이
Parent Span ID덕분에 각 서버가 제각각 트레이스 조각(Span)을Grafana Tempo로 던져도, Tempo가 퍼즐을 맞추듯 정확한 폭포수 계단 모양(Waterfall Chart) 으로 호출 순서를 재조립할 수 있습니다!
- 택배가 인천 물류센터(
3. 서비스 메시는 어떻게 코드 수정 없이 트레이스를 만들어낼까? (OTLP & 헤더 전파)
원래 서비스 메시가 없을 때는 개발자가 모든 애플리케이션 코드마다 OpenTelemetry SDK 라이브러리를 설치하고 설정해야 트레이스가 나왔습니다.
하지만 Istio 서비스 메시(Waypoint / Envoy) 환경에서는 다음과 같이 인프라 수준에서 자동으로 트레이스(Span)를 생성하고 전송합니다!
sequenceDiagram
autonumber
participant Client as study-client 파드
participant WP as Waypoint Proxy (Envoy L7)
participant App as order-api 파드
participant Alloy as Grafana Alloy (:4317)
participant Tempo as Grafana Tempo (:3200)
Client->>WP: 1. GET /trace-test 호출
Note over WP: 2. 트레이스 헤더(traceparent, x-b3-traceid,
x-request-id) 자동 생성 및 스탬프 날인!
출발 시각 기록!
WP->>App: 3. 헤더가 찍힌 요청을 order-api로 전달
App-->>WP: 4. 200 OK 응답 반환 (실제 echo 본문에 찍힌 헤더 확인 가능!)
Note over WP: 5. 종료 시각 기록 후 Span 완성!
WP--)Alloy: 6. 비동기 OTLP gRPC (:4317)로 Span 초고속 전송!
Alloy--)Tempo: 7. Tempo 저장소로 전달 및 인덱싱 완료!W3C Trace Context (traceparent), B3 헤더, 그리고 OTLP
W3C Trace Context(traceparent헤더):- 과거에는 Zipkin의
x-b3-traceid방식, Jaeger의uber-trace-id방식 등 회사마다 헤더 이름이 달라서 호환이 안 되었습니다. 이를 통일하기 위해 월드와이드웹 표준 기구(W3C)가 제정한 전 세계 공통 HTTP 트레이스 헤더가 바로traceparent입니다! - 형태:
traceparent: 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01
(버전(00)-32자리 Trace ID-16자리 Parent Span ID-샘플링여부(01))
- 과거에는 Zipkin의
- 컨텍스트 헤더 전파 (Header Propagation — 실무 개발자와의 협업 포인트!):
Waypoint Proxy는 요청이 지나갈 때마다 자동으로traceparent,x-request-id,x-b3-traceid헤더를 만들어 붙여 주고 자기 구간의Span을 Tempo로 보냅니다.- 단, 만약
order-api가 요청을 받은 뒤 또 다른 뒷단 API(payment-api)를 새로 호출한다면, 두 구간의 바코드가 끊어지지 않고 하나의Trace ID로 묶이도록order-api코드에서 들어온 요청의 트레이스 헤더(traceparent,x-request-id)를 뒷단 요청 헤더에 그대로 복사해 넘겨주기(Header Forwarding) 만 하면 전체 체인이 하나로 완벽히 이어집니다!
OTLP(OpenTelemetry Protocol, 포트4317/4318):- Envoy/
Waypoint가 생성한 트레이스 데이터를 수집기(Grafana Alloy)로 쏴줄 때 사용하는 국제 표준 전송 규약입니다. 고속 바이너리 통신인 gRPC 방식은 항상4317번 포트, HTTP 방식은4318번 포트를 사용합니다.
- Envoy/
4. 왜 Jaeger 대신 Grafana Tempo 인가? (TraceQL)
과거에는 분산 추적 저장소로 Jaeger나 Zipkin을 많이 썼지만, 이들은 대용량 환경에서 무거운 Elasticsearch나 Cassandra DB를 백엔드로 요구했습니다.
반면 Grafana Tempo 는 앞서 배운 Grafana Loki와 똑같은 철학으로 설계되었습니다:
- 외부 DB 의존성 제로(Zero Dependency): 무거운 색인 DB 없이 오직 저렴한 로컬 디스크나 클라우드 객체 스토리지(AWS S3, KT Cloud Object Storage)만으로 초당 수십만 개의 Span을 거뜬히 저장합니다.
TraceQL지원: Prometheus의PromQL, Loki의LogQL과 문법 스타일을 통일한TraceQL을 사용해{ span.http.status_code = 500 && duration > 100ms }처럼 정교하게 문제의 트레이스만 골라낼 수 있습니다.- LGTM 완벽 연동: Grafana 화면에서 Tempo의 트레이스 바(
Span) 하나를 클릭하면, 그 순간 그 파드가 남긴 Loki 로그와 VictoriaMetrics 메트릭으로 1초 만에 점프합니다!
🔗 다음 단계 (실습 검증)
이론으로 배운 LGTM의 세 번째 기둥인 Grafana Tempo (2.7.1) 와 Istio OpenTelemetry 트레이싱 파이프라인을 클러스터에서 직접 검증해 봅니다!
- Istio
meshConfig에otel-tracing프로바이더(alloy.monitoring.svc.cluster.local:4317)를 등록하고Telemetry리소스로 샘플링 비율을100%로 켭니다. order-api가 되돌려주는 응답 본문 속에서Waypoint가 자동으로 찍어 넣은x-b3-traceid/x-request-id헤더 실물을 눈으로 확인하고,- Tempo의 검색 API(
/api/search)와 상세 조회 API(/api/traces/<TraceID>)를 호출해 실제 생성된Trace ID와Span데이터를 100% 실측합니다!
네비게이션
| 이전 | 목록 | 다음 |
|---|---|---|
| ◀ Part 09 실습 | 목록으로 | Part 10 실습 ▶ |